
#include "SelectDispatcher.h"

SelectDispatcher::SelectDispatcher(EventLoop *eventLoop)
    :Dispatcher(eventLoop)
{
    FD_ZERO(&this->m_readset);
    FD_ZERO(&this->m_writeSet);
    this->m_name = "select";
}

int SelectDispatcher::add()
{
    // 判断fd是否超过了最大值
    if (this->m_channel->getSocket() >= this->m_maxSize)
    {
        return -1;
    }
    setFdSet();
    return 0;
}
// 移除 ,把一个节点从epoll树上删除
int SelectDispatcher::remove()
{
    clearFdSet();
    // 通过channel释放对应的TcpConnection 的资源
    this->m_channel->destoryCallBack(const_cast<void *>(this->m_channel->getArg()));
    channel->destoryCallBack(channel->arg);
    return 0;
}
// 修改把一个节点从epoll树上修改
int SelectDispatcher::modify()
{
    setFdSet();
    clearFdSet();
    return 0;
}
// 事件检测 ，检测epoll树上是否有事件发生
int SelectDispatcher::dispatch(int timeout = 2) // 单位秒
{
    // 检测是否有数据发生咸亨
    struct timeval tim;
    tim.tv_sec = timeout;
    tim.tv_usec = 0;
    fd_set rdtmp = data->readset;
    fd_set wdtmp = data->writeSet;
    int count = select(this->m_maxSize, &rdtmp, &wdtmp, NULL, &tim);
    if (count == -1)
    {
        perror("select error");
    }
    for (int i = 0; i < this->m_maxSize; ++i)
    {
        if (FD_ISSET(i, &rdtmp))
        {
            // 读事件就绪了，执行回调函数
            eventActivate(eventLoop, i, ReadEvent);
        }

        if (FD_ISSET(i, &wdtmp))
        {
            // 写事件就绪了，执行回调函数
            eventActivate(eventLoop, i, WriteEvent);
        }
    }
    return 0;
}

SelectDispatcher::~SelectDispatcher()
{
}

void SelectDispatcher::setFdSet()
{
    if (this->m_channel->getEvent() & static_cast<int>(FDEvent::ReadEvent))
    {
        FD_SET(this->m_channel->getSocket(), &this->m_readset);
    }
    if (this->m_channel->getEvent() & static_cast<int>(FDEvent::WriteEvent))
    {
        FD_SET(this->m_channel->getSocket(), &this->m_writeSet);
    }
}
void SelectDispatcher::clearFdSet();
{
    if (this->m_channel->getEvent() & static_cast<int>(FDEvent::ReadEvent))
    {
        FD_CLR(this->m_channel->getSocket(), &this->m_readset);
    }
    if (this->m_channel->getEvent() & static_cast<int>(FDEvent::WriteEvent))
    {
        FD_CLR(this->m_channel->getSocket(), &this->m_writeSet);
    }
}

